package com.jinyu.admin.controller.sys;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.jinyu.admin.service.sys.SysUserService;
import com.jinyu.admin.utils.RedisUtils;
import com.jinyu.common.base.ApiRestResponse;
import com.jinyu.common.exception.BaseRuntimeException;
import com.jinyu.common.utils.ServletUtils;
import com.jinyu.dao.entity.sys.LoginModel;
import com.jinyu.dao.entity.sys.SysUser;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.net.http.HttpResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: yangli
 * @Despriction:    用户登录或者注销的控制器
 * @Package: com.jinyu.admin.controller.sys
 * @Date:Created in 2022/5/4 17:01
 * @Modify By:
 */
@Slf4j
@RestController
@RequestMapping("/base")
public class LoginAndOutController {
    private static final int WIDTH = 160;
    private static final int HEIGHT = 60;


    @Autowired
    private SysUserService sysUserService;


    @Value("${sa-token.refresh-token-timeout}")
    private Long refreshTokenTimeOut;


    /**
     *  用户登录 - 不用校验token
     * @param loginModel    登录信息
     * @return  ApiRestResponse
     */
    @PostMapping("/doLogin")
    public ApiRestResponse<Map<String,String>> doLogin(@RequestBody @Valid LoginModel loginModel, HttpServletResponse response) {
        SysUser sysUser = sysUserService.selectByOne(loginModel.getUserName());
        if (Objects.isNull(sysUser)) {
            return ApiRestResponse.err("登录失败，账号错误");
        }
        String md5Password = SaSecureUtil.md5(loginModel.getPassWord());
        if (!md5Password.equals(sysUser.getPassWord())) {
            log.error("密码错误：{}" ,loginModel.getPassWord());
            return ApiRestResponse.err("登录失败，密码错误");
        }
        StpUtil.login(sysUser.getUserCode(), new SaLoginModel().setDevice(loginModel.getDeviceType()));
        //记录登录人以及登录设备
        //String refreshToken = SaTempUtil.createToken(sysUser.getUserCode()+"-"+loginModel.getDeviceType(), refreshTokenTimeOut);

        Map<String, String> tokenMap = MapUtil.createMap(HashMap.class);
        tokenMap.put("token",StpUtil.getTokenValue());
        //tokenMap.put("refreshToken",refreshToken);
        return ApiRestResponse.ok("登录成功", tokenMap);
    }


    /***
     * 无状态token续期
     * @return ApiRestResponse
     */
    @PostMapping("/refreshToken")
    public ApiRestResponse<Map<String,String>> refreshToken() {

        String refreshToken = ServletUtils.getHeader( "REFRESH_TOKEN");
        String token = ServletUtils.getHeader( "TOKEN");
        //不存在token或者refreshToken过期
        if(StrUtil.isBlank(refreshToken)||StrUtil.isBlank(token)||SaTempUtil.getTimeout(refreshToken)<=0){
            throw new BaseRuntimeException("登录失效，请重新登录");
        }

        //token未过期 不允许刷新
        long tokenTimeout = StpUtil.getTokenTimeout();
        if(tokenTimeout>0){
            throw new BaseRuntimeException("禁止恶意刷新Token,否则将会账号封禁");
        }
        //获取登录人和登录设备
        String[] split = SaTempUtil.parseToken(refreshToken).toString().split("-");

        //重新登录和生成token
        StpUtil.login(split[0], new SaLoginModel().setDevice(split[1]));
         refreshToken = SaTempUtil.createToken(String.join("-",split), refreshTokenTimeOut);


        Map<String, String> tokenMap = MapUtil.createMap(HashMap.class);
        tokenMap.put("token",StpUtil.getTokenValue());
        tokenMap.put("refreshToken",refreshToken);
        return ApiRestResponse.ok("登录成功", tokenMap);

    }
    /**
     *  用户注销
     * @return  ApiRestResponse
     */
    @GetMapping("/doLogout")
    public ApiRestResponse<Object> doLogout() {
        //获取当前用户的token信息
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        //当前账号的userCode
        Object loginId = tokenInfo.getLoginId();
        //当前账号的登录设备
        String loginDevice = tokenInfo.getLoginDevice();
        //注销当前账号登录设备的token
        StpUtil.logout(loginId,loginDevice);
        return ApiRestResponse.ok("注销成功");
    }

    /**
     *  指定账号指定端踢人下线
     * @param userCode  用户编码
     * @param deviceType    登录设备类型
     * @return  ApiRestResponse
     */
    @GetMapping("/doKickOut")
    public ApiRestResponse<Void> doKickout(@RequestParam("userCode") String userCode
            ,@RequestParam(value = "deviceType",required = false) String deviceType) {
        if (StrUtil.isNotBlank(deviceType))
            StpUtil.kickout(userCode, deviceType);
        else
            StpUtil.kickout(userCode);
        return ApiRestResponse.ok("踢人下线成功");
    }


    /**
     * 生成验证码
     */
    @GetMapping("/captchaImage")
    public ApiRestResponse<Map<String, Object>> getCode() {
        Map<String, Object> captchaMap = new HashMap<>();
        // 保存验证码信息
        String uuid = IdUtil.simpleUUID();
        String CAPTCHA_CODE_KEY = "captcha_codes:";
        String verifyKey = CAPTCHA_CODE_KEY + uuid;
        // 生成4位字符验证码
        CodeGenerator codeGenerator =new RandomGenerator(4);
        ShearCaptcha captcha = new ShearCaptcha(WIDTH,HEIGHT);
        captcha.setGenerator(codeGenerator);
        captcha.createCode();
        String code = captcha.getCode();
        //将验证码存入缓存
        RedisUtils redisUtils = SpringUtil.getBean(RedisUtils.class);
        redisUtils.setCacheObject(verifyKey, code, 60L, TimeUnit.SECONDS);

        captchaMap.put("uuid", uuid);
        captchaMap.put("img", captcha.getImageBase64());
        return ApiRestResponse.ok(captchaMap);
    }
}
